<template>
  <view class="custom-tree">
    <view class="tree-node" v-for="(item, index) in list" :key="item.data[fieldsName.key]">
      <view
        v-if="customRender"
        class="tree-node-content_custom"
        :class="{
          'collapse-icon': item.data[fieldsName.children] && item.data[fieldsName.children].length,
          'collapse-icon_expand': list.findIndex(({ parent }) => parent === item.data[fieldsName.key]) !== -1,
        }"
        @click="handleClick(item, index)"
      >
        <slot :slotData="item.data" :indent="item.indent"></slot>
      </view>

      <view
        v-else
        class="tree-node-content action-icon"
        :class="{
          'collapse-icon': item.data[fieldsName.children] && item.data[fieldsName.children].length,
          'collapse-icon_expand': list.findIndex(({ parent }) => parent === item.data[fieldsName.key]) !== -1,
        }"
        @click="handleClick(item, index)"
      >
        <view class="indent" v-for="i in item.indent" :key="i"></view>
        <view class="content">{{ item.data[fieldsName.label] }}</view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  props: {
    items: {
      type: Array,
      default: () => [],
    },
    fieldsName: {
      type: Object,
      default: () => ({
        key: "key",
        label: "label",
        children: "children",
      }),
    },
    customRender: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      list: [],
    };
  },
  mounted() {},
  watch: {
    items(val) {
      this.list = this.makeList(val);
    },
  },
  methods: {
    hanldeEmit(emitName, params) {
      this.$emit(emitName, params);
    },
    makeList(valuse, indent = 0, parent = 0) {
      const list = [];
      valuse.forEach((data) => {
        list.push({ data, indent, parent });
      });
      return list;
    },
    getChildrenKeys(values, list = {}) {
      values.forEach((item) => {
        list[`${item[this.fieldsName.key]}`] = true;
        if (item[this.fieldsName.children] && item[this.fieldsName.children].length) {
          this.getChildrenKeys(item[this.fieldsName.children], list);
        }
      });
      return list;
    },
    handleClick({ data, indent }, index) {
      const key = data[this.fieldsName.key];
      const children = data[this.fieldsName.children];

      // 判断是否存在当前节点的子节点 > 不存在(-1) 添加 >> 存在 删除
      const currentIndex = this.list.findIndex(({ parent }) => parent === key);
      if (currentIndex === -1) {
        if (children && children.length > 0) {
          const items = this.makeList(children, indent + 1, key);
          this.list.splice(index + 1, 0, ...items);
        }
      } else {
        // 获取当前节点以下的所有节点 childrenKeys
        const childrenKeys = this.getChildrenKeys(data[this.fieldsName.children]);
        // 删除当前节点以下的所有节点
        this.list = this.list.filter(({ data }) => !childrenKeys[data[this.fieldsName.key]]);
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.custom-tree {
  width: 100%;

  .tree-node {
    width: 100%;

    .tree-node-content_custom {
      width: 100%;
      box-sizing: border-box;
      position: relative;
      background-color: #fff;
      border-bottom: 1px solid #f5f5f5;
    }

    .tree-node-content {
      width: 100%;
      box-sizing: border-box;
      position: relative;
      display: flex;
      flex-direction: row;
      align-items: center;
      background-color: #fff;
      border-bottom: 1px solid #f5f5f5;

      .indent {
        width: 16px;
        height: 16px;
      }

      .content {
        width: 100%;
        box-sizing: border-box;
        padding: 12px 16px;
        font-size: 14px;
      }

      .action-icon {
        content: "";
        right: 16px;
        top: calc(50% - 6px);
        height: 10px;
        width: 10px;
        border-width: 2px 2px 0 0;
        border-color: silver;
        border-style: solid;
        -webkit-transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
        transform: matrix(0.5, 0.5, -0.5, 0.5, 0, 0);
        position: absolute;
      }
    }

    .collapse-icon {
      position: relative;
      &::before {
        content: "";
        position: absolute;
        right: 16px;
        top: calc(50% - 5px);
        height: 8px;
        width: 8px;
        border-width: 2px 2px 0 0;
        border-color: silver;
        border-style: solid;
        -webkit-transform: scale(0.8) rotate(45deg);
        transform: scale(0.8) rotate(45deg);
        transition: transform 0.3s;
      }
      &_expand::before {
        -webkit-transform: scale(0.8) rotate(135deg);
        transform: scale(0.8) rotate(135deg);
      }
    }
  }
}
</style>
